package org.server;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import org.model.ChatStrings;
import org.model.Friend;
import org.model.NetAddress;

import roby.privateEncryption.KeyGenerator;

public class ChattingServer {

	public static void main(String[] args) {
		new ChattingServer();
	}
	private HashMap<ServerListener, Friend> listOfUsers;
	private ServerSocket serverSocket;
	private byte[] privateGeneratedKey;
	private ServerClientHandler clientHandler;
	public ChattingServer()
	{
		clientHandler = new ServerClientHandler();
		listOfUsers = new HashMap<ServerListener, Friend>();
		boolean isBind = false;
		int port = 1500;
		while(!isBind)
		{
			try {
				
				serverSocket = new ServerSocket(port);
				System.out.println("Server is opened");
				isBind = true;
				KeyGenerator.createKey();
				privateGeneratedKey = KeyGenerator.getKey();
				System.out.println(privateGeneratedKey.length);
				System.out.println(privateGeneratedKey[0]);
				while(true)
				{
					Socket tempSocket = serverSocket.accept();
					new ServerListener(tempSocket).start();
				}
			} catch (Exception e) {
				port++;
				System.err.println("error starting the server with port"+port);
			}
		}
	}
	
	private class ServerListener extends Thread
	{
		private Socket mSocket;
		private DataOutputStream outputStream;
		private BufferedReader inputStream;
		public ServerListener(Socket tempSocket) {
			mSocket = tempSocket;			
		}
		public void updateNewFriend(Friend friend)
		{
			try {
				outputStream.writeBytes("in"+ChatStrings.END_LINE);
				outputStream.writeBytes(friend.getAddress().getPort()+ChatStrings.END_LINE);
				outputStream.write(friend.getAddress().getIpAddress());
				outputStream.writeBytes(friend.getName()+ChatStrings.END_LINE);	
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		public void removeFriend(Friend friend)
		{
			try {
				outputStream.writeBytes("out"+ChatStrings.END_LINE);
				outputStream.writeBytes(friend.getAddress().getPort()+ChatStrings.END_LINE);
				outputStream.write(friend.getAddress().getIpAddress());
				outputStream.writeBytes(friend.getName()+ChatStrings.END_LINE);	
			} catch (Exception e) {
				//e.printStackTrace();
				System.out.println("1-Client closing too fast");
				
			}
		}
		@Override
		public void run() {
			super.run();
			
			try {
				//-i modified here
				outputStream = new DataOutputStream(mSocket.getOutputStream());
				inputStream  = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
				//outputStream.setPrivateKey(privateGeneratedKey);
				//inputStream.setPrivateKey(privateGeneratedKey);
				outputStream.write(privateGeneratedKey);
				//-
				String name = inputStream.readLine();
				String pass = inputStream.readLine();
				if(!clientHandler.isClientExists(name, pass))
				{
					outputStream.writeBytes("-1"+ChatStrings.END_LINE);
					return;
				}
				outputStream.writeBytes("1"+ChatStrings.END_LINE);
				//System.out.println(name);
				char[] address = new char[4];
				inputStream.read(address);
				for (int i = 0; i < address.length; i++) {
					System.out.print((int)address[i]+".");
				}
				//System.out.println();
				Integer cport = Integer.parseInt(inputStream.readLine());
				System.out.println(cport);
				Friend friend = new Friend(name,new NetAddress(cport,address));
				
				Iterator<Entry<ServerListener, Friend>> listIter = listOfUsers.entrySet().iterator();
				while(listIter.hasNext())
				{
					Entry<ServerListener, Friend> currentItem = listIter.next();
					Friend f = currentItem.getValue();
					outputStream.writeBytes(String.valueOf(f.getAddress().getPort())+ChatStrings.END_LINE);
					outputStream.write(f.getAddress().getIpAddress());
					outputStream.writeBytes(f.getName()+ChatStrings.END_LINE);
				}
				outputStream.writeBytes("-1"+ChatStrings.END_LINE);
				
				//-update other nodes
				Iterator<Entry<ServerListener, Friend>> iter = listOfUsers.entrySet().iterator();
				while (iter.hasNext()) {
					Entry<ServerListener, Friend> item = (Entry<ServerListener, Friend>) iter.next();
					item.getKey().updateNewFriend(friend);
				}
				
				
				listOfUsers.put(this,friend);
				String line = inputStream.readLine();
				
				if(line.startsWith("logOut"))
				{
					int port = Integer.parseInt(line.substring(line.indexOf('t')+1));
					address = new char[4];
					inputStream.read(address);
					NetAddress outAddress = new NetAddress(port,address);
					iter = listOfUsers.entrySet().iterator();
					
					ServerListener key = null;
					while (iter.hasNext()) {
						Entry<ServerListener, Friend> item = (Entry<ServerListener, Friend>) iter.next();
						if(!item.getValue().getAddress().equals(outAddress))
						{
							item.getKey().removeFriend(friend);
						}
						else
							key = item.getKey();
						
					}	
					listOfUsers.remove(key);
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("2-closing clients so fast");
			}
			
		}		
	}
}
